package org.koin.core.component;

import org.koin.core.error.NoScopeDefFoundException;
import org.koin.core.error.ScopeAlreadyCreatedException;
import org.koin.core.qualifier.TypeQualifier;
import org.koin.core.scope.Scope;
import org.koin.ext.ClassUtil;

public abstract class KoinScopeComponent implements KoinComponent {

    protected Scope scope;

    public static <T> String getScopeId(T t) {
        return ClassUtil.getFullName(t.getClass()) + "@" + t.hashCode();
    }

    public static <T> TypeQualifier getScopeName(T t) {
        return new TypeQualifier(t.getClass());
    }

    public static <T extends KoinScopeComponent> Scope crateScope(T t, Object source)
            throws ScopeAlreadyCreatedException,
            NoScopeDefFoundException {
        return t.getKoin().createScope(getScopeId(t), getScopeName(t), source);
    }

    public static <T extends KoinScopeComponent> Scope getScopeOrNull(T t) {
        return t.getKoin().getScopeOrNull(getScopeId(t));
    }

    public static <T extends KoinScopeComponent> Scope newScope(T t)
            throws ScopeAlreadyCreatedException,
            NoScopeDefFoundException {
        return crateScope(t, null);
    }

    public static <T extends KoinScopeComponent> Scope getOrCreateScope(T t)
            throws ScopeAlreadyCreatedException,
            NoScopeDefFoundException {
        Scope scope = getScopeOrNull(t);
        if (scope == null) {
            scope = crateScope(t, null);
        }
        return scope;
    }

    public Scope getScope() {
        if (scope == null) {
            scope = initScope();
        }
        return scope;
    }

    protected abstract Scope initScope();

    public void closeScope() {
        if (getScope() != null && getScope().isNotClosed()) {
            getScope().close();
        }
    }
}
